<?php

/**
 * 先进先出
 * @copyright   Copyright (c) 2006 - 2010 DZH 友拓软件友拓通
 * @category   	先进先出
 * @package  	Model
 * @author    	黄明兴
 * @version 	2.1,2012-07-22
*/

class FiFoPublicModel extends Model {
	protected $tableName = 'stock_in';
	private $params 		= array();
	private $storage_attr 	= array();
	private $all_relation_type	= array(
						'loadContainer'		=> 1,
						'instock'			=> 2,
						'saleOrder'			=> 3,
						'adjust'			=> 4,
						'returnSaleOrder' 	=> 5,
						'transfer' 			=> 6,
						'delivery'			=> 7,
						'initStorage'		=> 8,
						'profitandloss'		=> 9,
						
	);
	private $relation_type = '';
	/**
	 * 更新库存公共接口
	 *
	 * @param  参数 $params
	 * @param  方法名称，默认取模块名称，首字母转小写
	 */
	public function run($params){
		$this->_module = $params['_module'];
		$this->_action = $params['_action'];
		$method_name = ucwords_first($this->_module);
		$this->params = $params;
		$this->relation_type = $this->all_relation_type[$method_name];
		$this->$method_name();
	}
	
	
	/**
	 * 入库更新stock_in记录
	 *
	 */
	private function instock(){
		// 删除在流程中删除的记录
		$this->db->execute('delete from stock_in where main_id='.$this->params['id'].' and relation_type='.$this->relation_type.' and detail_id in(select id from instock_detail_del where instock_id='.$this->params['id'].')');
		$main 	= M('Instock')->find($this->params['id']);
		$sql 	= 'select * from instock_detail where instock_id='.$this->params['id'].' order by id asc';
		$detail = $this->db->query($sql);
		foreach ((array)$detail as $value) {
			$this->setStockInData($value,$main,'real_arrive_date');
		}
		$this->synchronismStockOut();
	}
	
	
	/**
	 * 期初库存更新stock_in记录
	 *
	 */
	private function initStorage(){
		// 删除在流程中删除的记录
		$this->db->execute('delete from stock_in where main_id='.$this->params['id'].' and relation_type='.$this->relation_type.' and detail_id in(select id from init_storage_detail_del where init_storage_id='.$this->params['id'].')');
		$main 	= M('InitStorage')->find($this->params['id']);
		$sql 	= 'select * from init_storage_detail where init_storage_id='.$this->params['id'].' order by id asc';
		$detail = $this->db->query($sql);
		foreach ((array)$detail as $value) {
			$this->setStockInData($value,$main,'init_storage_date');
		}
		$this->synchronismStockOut();
	}
	
	/**
	 * 退货库存更新stock_in记录
	 *
	 */
	private function returnSaleOrder(){
		// 删除在流程中删除的记录
		$this->db->execute('delete from stock_in where main_id='.$this->params['id'].' and relation_type='.$this->relation_type.' and detail_id in(select id from return_sale_order_detail_del where return_sale_order_id='.$this->params['id'].')');
		$main 	= M('ReturnSaleOrder')->find($this->params['id']);
		$sql 	= 'select * from return_sale_order_detail where return_sale_order_id='.$this->params['id'].' order by id asc';
		$detail = $this->db->query($sql);
		foreach ((array)$detail as $value) {
			if ($value['is_use']==1) {
				$this->setStockInData($value,$main,'return_order_date');
			}else {
				// 修改记录从可用改为不可用删除明细记录
				$value['id'] > 0 && $this->db->execute('delete from stock_in where main_id='.$this->params['id'].' and relation_type='.$this->relation_type.' and detail_id='.$value['id']);
			}
		}
		$this->synchronismStockOut();
	}
	
	
	/**
	 * 盈亏库存更新stock_in记录
	 *
	 */
	private function profitandloss(){
		// 盈亏单不可修改，删除，无需处理历史数据
		if (ACTION_NAME!='update') {return true;}
		$main 	= M('Profitandloss')->find($this->params['id']);
		$sql 	= 'select * from profitandloss_detail where profitandloss_id='.$this->params['id'].' order by id asc';
		$detail = $this->db->query($sql);
		foreach ((array)$detail as $value) {
			$value['quantity'] = $value['stocktake_quantity']-$value['storage_quantity'];
			if ($value['quantity']>0) {
				$this->setStockInData($value,$main,'profitandloss_date');
				$this->synchronismStockOut();
			}else {
				$this->setStockOutData($value,$main,'profitandloss_date');
			}
		}
	}
	
	
	/**
	 * 销售更新stock_out记录
	 *
	 */
	private function saleOrder(){
		// 配置有发货流程时不记录先进先出
		if (C('sale.relation_sale_follow_up')==1) {return true;}
		$this->restoreStockOut();		// 还原出库记录
		$main 	= M('SaleOrder')->find($this->params['id']);
		$sql 	= 'select * from sale_order_detail where sale_order_id='.$this->params['id'].' order by id asc';
		$detail = $this->db->query($sql);
		foreach ((array)$detail as $value) {
			$this->setStockOutData($value,$main,'order_date');
		}
	}
	
	
	/**
	 * 发货stock_out记录
	 *
	 */
	private function delivery(){
		$this->restoreStockOut();		// 还原出库记录
		$main 	= M('Delivery')->find($this->params['id']);
		$sql 	= 'select * from delivery_detail where delivery_id='.$this->params['id'].' order by id asc';
		$detail = $this->db->query($sql);
		foreach ((array)$detail as $value) {
			// 发货表没有记录币种ID，需要去销售表获取
			$temp	= M('SaleOrder')->field('currency_id')->find($value['sale_order_id']);
			$value['currency_id'] = $temp['currency_id'];
			$this->setStockOutData($value,$main,'delivery_date');
		}
	}
	
	
	
	
	/**
	 * 库存调整stock_in  stock_out 记录
	 */
	
	private function adjust(){
		// 删除在流程中删除的记录
		$this->db->execute('delete from stock_in where main_id='.$this->params['id'].' and relation_type='.$this->relation_type.' and detail_id in(select id from adjust_detail_del where adjust_id='.$this->params['id'].')');
		$this->restoreStockOut();		// 还原出库记录
		$main 	= M('Adjust')->find($this->params['id']);
		$sql 	= 'select * from adjust_detail where adjust_id='.$this->params['id'].' order by id asc';
		$detail = $this->db->query($sql);
		foreach ((array)$detail as $value) {
			$data = $rate = $rs = '';
			if ($value['quantity']>0) {
				$this->setStockInData($value,$main,'adjust_date');
			}else {
				$this->setStockOutData($value,$main,'adjust_date');
			}
		}
		$this->synchronismStockOut();
	}
	
	/**
	 *调拨更新stock_in，stock_out记录
	 *
	 */
	private function transfer(){
		// 删除在流程中删除的记录
		$this->db->execute('delete from stock_in where main_id='.$this->params['id'].' and relation_type='.$this->relation_type.' and detail_id in(select id from transfer_detail_del where transfer_id='.$this->params['id'].')');
		$this->restoreStockOut();		// 还原出库记录
		$main 	= M('Transfer')->find($this->params['id']);
		$sql 	= 'select * from transfer_detail where transfer_id='.$this->params['id'].' order by id asc';
		$detail = $this->db->query($sql);
		// 调拨需要特殊处理，先出库再入库，出库的金额取对应入库单金额，入库金额取对应出库单金额
		foreach ((array)$detail as $value) {
			$in_warehouse_id 	= $value['in_warehouse_id'];
			$out_warehouse_id	= $value['warehouse_id'];
			$this->transferStockOutData($value,$main);
		}
		$this->synchronismStockOut();
	}
	
	/**
	 * 调拨添加stock_out，stock_in记录
	 *
	 * @param  array $value 明细数据
	 * @param  array $main 主表数据
	 * @param  string $date_field 日期字段名称
	 */
	private function transferStockOutData($value,$main){
		$data 						= array();
		$data['main_id'] 			= $main['id'];
		$data['detail_id'] 			= $value['id'];
		$data['out_relation_type'] 	= $this->relation_type;
		$data['out_warehouse_id'] 	= $value['warehouse_id'];
		$data['out_date'] 			= $main['transfer_date'];
		$data['product_id'] 		= $value['product_id'];
		$data['color_id'] 			= C('storage_color') ? $value['color_id'] : 0;
		$data['size_id'] 			= C('storage_size') ? $value['size_id'] : 0;
		$data['capability'] 		= C('storage_format')>=2 ? $value['capability'] : 1;
		$data['dozen'] 				= C('storage_format')>=3 ? $value['dozen'] : 1;
		$data['mantissa'] 			= C('storage_mantissa') ? $value['mantissa'] : 1;
		$out_quantity = $rs = '';
		$out_quantity = abs($value['quantity']);
		while ($out_quantity>0) {
			// 根据入库日期降序，先入库的先出库，每次只取一条记录
			$sql = 'select * from stock_in where product_id='.$data['product_id'].' and color_id='.$data['color_id'].' and size_id='.$data['size_id'].' and capability='.$data['capability'].' and dozen='.$data['dozen'].' and mantissa='.$data['mantissa'].' and balance>0 order by in_date asc,id asc limit 0,1';
			$temp 	= $this->db->query($sql);
			$rs 	= $temp[0];
			if (empty($rs)) {
				rollback();
				throw_json('先进先出获取入库记录出错，请立即联系客服人员！');
			}
			$data['stock_in_id'] 			= $rs['id'];
			$data['in_warehouse_id'] 		= $rs['warehouse_id'];
			$data['in_date'] 				= $rs['in_date'];
			$data['in_currency_id'] 		= $rs['currency_id'];
			$data['in_price'] 				= $rs['price'];
			$data['in_base_price'] 			= $rs['base_price'];
			$data['in_relation_type'] 		= $rs['relation_type'];
			$data['base_delivery_price'] 	= $rs['base_delivery_price'];
			// 计算本位币单价
			$data['base_currency_id'] 	= $rs['base_currency_id'];
			$data['rate'] 				= $rs['rate'];
			$data['out_base_price'] 	= $rs['base_price'];
			$data['out_currency_id'] 	= $rs['currency_id'];
			$data['out_price'] 			= $rs['price'];
		
			// 判断本次入库数量是否足够出库
			if ($out_quantity<=$rs['balance']) {
				$data['quantity'] 	= $out_quantity;
				$this->db->execute('update stock_in set balance=balance-'.$out_quantity.' where id='.$rs['id']);
				M('StockOut')->add($data);
				// 出库添加成功同时添加一笔入库记录
				unset($rs['id']);
				$rs['quantity']			= $rs['balance'] = $out_quantity;
				$rs['in_date']			= $main['transfer_date'];
				$rs['main_id'] 			= $main['id'];
				$rs['detail_id'] 		= $value['id'];
				$rs['warehouse_id'] 		= $value['in_warehouse_id'];
				$rs['relation_type'] = $this->relation_type;
				$this->add($rs);
				break;
			}else {
				$data['quantity'] 	= $rs['balance'];
				$this->db->execute('update stock_in set balance=0 where id='.$rs['id']);
				M('StockOut')->add($data);
				$out_quantity -= $rs['balance'];
				// 出库添加成功同时添加一笔入库记录
				unset($rs['id']);
				$rs['quantity']			= $rs['balance'];
				$rs['in_date']			= $main['transfer_date'];
				$rs['main_id'] 			= $main['id'];
				$rs['detail_id'] 		= $value['id'];
				$rs['warehouse_id'] 	= $value['in_warehouse_id'];
				$rs['relation_type'] = $this->relation_type;
				$this->add($rs);
			}
		}
		
	}
	
	
	/**
	 * 添加stock_in记录
	 *
	 * @param  array $value 明细数据
	 * @param  array $main 主表数据
	 * @param  string $date_field 日期字段名称
	 */
	private function setStockInData($value,$main,$date_field){
		$data						= array();
		$data['main_id'] 			= $main['id'];
		$data['detail_id'] 			= $value['id'];
		$data['relation_type'] 		= $this->relation_type;
		$data['warehouse_id'] 		= $value['warehouse_id'] ? $value['warehouse_id'] : $main['warehouse_id'];
		$data['product_id'] 		= $value['product_id'];
		$data['color_id'] 			= C('storage_color') ? $value['color_id'] : 0;
		$data['size_id'] 			= C('storage_size') ? $value['size_id'] : 0;
		$data['quantity'] 			= $value['quantity'];
		$data['capability'] 		= C('storage_format')>=2 ? $value['capability'] : 1;
		$data['dozen'] 				= C('storage_format')>=3 ? $value['dozen'] : 1;
		$data['mantissa'] 			= C('storage_mantissa') ? $value['mantissa'] : 1;
		$data['currency_id'] 		= $value['currency_id'] ? $value['currency_id'] : $main['currency_id'];
		$data['price'] 				= $value['price'];
		$data['in_date'] 			= $main[$date_field];
		$data['discount'] 			= $value['discount']+0;
		// 计算本位币单价
		$rate = $this->getRate($data['currency_id'],$data['in_date']);
		$data['base_currency_id'] 	= C('currency');
		$data['rate'] 				= $rate;
		$data['base_price'] 		= $value['price']*$rate;
		if ($this->_module=='Instock') {
			$data['factory_id'] 			= $value['factory_id'];
			// 计算运费本位币单价
			if (C('instock.instock_logistics_funds')==1) {
				$data['delivery_price'] 		= $value['delivery_fee_detail'];
				$data['delivery_currency_id'] 	= $main['currency_id'];
				$rate = $this->getRate($main['currency_id'],$data['in_date']);
				$data['delivery_rate'] 			= $rate;
				$data['base_delivery_price'] 	= $value['delivery_fee_detail']*$rate;
			}
		}
		if ($this->_module=='ReturnSaleOrder') {
			$data['price']				= $value['return_base_price'];
			$data['base_price'] 		= $value['return_base_price']*$rate;
			$data['flow_price'] 		= $value['price'];
			$data['base_flow_price'] 	= $value['price']*$rate;
		}
		$rs = $this->field('id,quantity,balance')->where('relation_type='.$this->relation_type.' and main_id='.$main['id'].' and detail_id='.$value['id'])->find();
		if ($rs['id']>0) {
			$data['id'] = $rs['id'];
			$data['balance'] = $value['quantity']-($rs['quantity']-$rs['balance']);
			$this->save($data);
		}else {
			$data['balance'] = $value['quantity'];
			$this->add($data);
//			echo $this->getLastSql();
		}
	}
	
	/**
	 * 添加stock_out记录
	 *
	 * @param  array $value 明细数据
	 * @param  array $main 主表数据
	 * @param  string $date_field 日期字段名称
	 */
	private function setStockOutData($value,$main,$date_field){
		$data 						= array();
		$data['main_id'] 			= $main['id'];
		$data['detail_id'] 			= $value['id'];
		$data['out_relation_type'] 	= $this->relation_type;
		$data['out_warehouse_id'] 	= $value['warehouse_id'] ? $value['warehouse_id'] : $main['warehouse_id'];
		$data['out_date'] 			= $main[$date_field];
		$data['out_currency_id'] 	= $value['currency_id'] ? $value['currency_id'] : $main['currency_id'];
		$data['product_id'] 		= $value['product_id'];
		$data['color_id'] 			= C('storage_color') ? $value['color_id'] : 0;
		$data['size_id'] 			= C('storage_size') ? $value['size_id'] : 0;
		$data['capability'] 		= C('storage_format')>=2 ? $value['capability'] : 1;
		$data['dozen'] 				= C('storage_format')>=3 ? $value['dozen'] : 1;
		$data['mantissa'] 			= C('storage_mantissa') ? $value['mantissa'] : 1;
		$data['out_price'] 			= $value['price'];
		$value['discount'] && $data['discount'] = $value['discount'];
		// 计算本位币单价
		$rate = $this->getRate($data['out_currency_id'],$data['out_date']);
		$data['base_currency_id'] 	= C('currency');
		$data['rate'] 				= $rate;
		$data['out_base_price'] 	= $value['price']*$rate;
		
		$out_quantity = $rs = '';
		$out_quantity = abs($value['quantity']);
		while ($out_quantity>0) {
			// 根据入库日期降序，先入库的先出库，每次只取一条记录
			$sql = 'select * from stock_in where product_id='.$data['product_id'].' and color_id='.$data['color_id'].' and size_id='.$data['size_id'].' and capability='.$data['capability'].' and dozen='.$data['dozen'].' and mantissa='.$data['mantissa'].' and balance>0 order by in_date asc,id asc limit 0,1';
			$temp 	= $this->db->query($sql);
			$rs 	= $temp[0];
			if (empty($rs)) {
				rollback();
				throw_json('先进先出获取入库记录出错，请立即联系客服人员！');
			}
			$data['stock_in_id'] 			= $rs['id'];
			$data['in_main_id'] 			= $rs['main_id'];
			$data['in_detail_id'] 			= $rs['detail_id'];
			$data['in_relation_type'] 		= $rs['relation_type'];
			$data['in_warehouse_id'] 		= $rs['warehouse_id'];
			$data['in_date'] 				= $rs['in_date'];
			$data['in_currency_id'] 		= $rs['currency_id'];
			$data['in_price'] 				= $rs['price'];
			$data['in_base_price'] 			= $rs['base_price'];
			$data['base_delivery_price'] 	= $rs['base_delivery_price'];
			// 判断本次入库数量是否足够出库
			if ($out_quantity<=$rs['balance']) {
				$data['quantity'] 	= $out_quantity;
				$this->db->execute('update stock_in set balance=balance-'.$out_quantity.' where id='.$rs['id']);
				M('StockOut')->add($data);
//				echo M('StockOut')->getLastSql();
				break;
			}else {
				$data['quantity'] 	= $rs['balance'];
				$this->db->execute('update stock_in set balance=0 where id='.$rs['id']);
				M('StockOut')->add($data);
				$out_quantity -= $rs['balance'];
			}
		}
	}
	
	
	/**
	 * 添加stock_out记录由于关联记录需要修改
	 *
	 * @param  array $value 明细数据
	 * @param  string  $restore  是否还原对应入库记录
	 */
	private function setStockOutDataForRelation($value,$restore=true){
		// 所有信息都不改直接删除自身出库后重新分配
		$this->restoreStockOut($value['id'],$restore);
		$out_quantity = $value['quantity'];
		while ($out_quantity>0) {
			// 根据入库日期降序，先入库的先出库，每次只取一条记录
			$sql = 'select * from stock_in where product_id='.$value['product_id'].' and color_id='.$value['color_id'].' and size_id='.$value['size_id'].' and capability='.$value['capability'].' and dozen='.$value['dozen'].' and mantissa='.$value['mantissa'].' and balance>0 order by in_date asc,id asc limit 0,1';
			$temp 	= $this->db->query($sql);
			$rs 	= $temp[0];
			if (empty($rs)) {
				rollback();
				throw_json('先进先出获取入库记录出错，请立即联系客服人员！');
			}
			$value['stock_in_id'] 			= $rs['id'];
			$value['in_main_id'] 			= $rs['main_id'];
			$value['in_detail_id'] 			= $rs['detail_id'];
			$value['in_relation_type'] 		= $rs['relation_type'];
			$value['in_warehouse_id'] 		= $rs['warehouse_id'];
			$value['in_date'] 				= $rs['in_date'];
			$value['in_currency_id'] 		= $rs['currency_id'];
			$value['in_price'] 				= $rs['price'];
			$value['in_base_price'] 		= $rs['base_price'];
			$value['base_delivery_price'] 	= $rs['base_delivery_price'];
			// 判断本次入库数量是否足够出库
			unset($value['id']);
			if ($out_quantity<=$rs['balance']) {
				$value['quantity'] 	= $out_quantity;
				$this->db->execute('update stock_in set balance=balance-'.$out_quantity.' where id='.$rs['id']);
				M('StockOut')->add($value);
//				echo M('StockOut')->getLastSql();
				break;
			}else {
				$value['quantity'] 	= $rs['balance'];
				$this->db->execute('update stock_in set balance=0 where id='.$rs['id']);
				M('StockOut')->add($value);
				$out_quantity -= $rs['balance'];
			}
		}
		
	}
	
	/**
	 * 修改入库记录时同步对应的出库信息
	 *
	 */
	private function synchronismStockOut(){
		// 获取删除的记录更新对应出库记录信息
		$sql = 'select * from stock_out where stock_in_id=0 and in_main_id='.$this->params['id'].' and in_relation_type='.$this->relation_type;
		$detail = $this->db->query($sql);
		foreach ((array)$detail as $value) {
			$this->setStockOutDataForRelation($value);
		}
		// 获取指定出库数量大于入库数量的记录更新对应出库记录信息
		$sql = 'select id,quantity from stock_in where balance<0 and main_id='.$this->params['id'].' and relation_type='.$this->relation_type;
		$detail = $this->db->query($sql);
		foreach ((array)$detail as $value) {
			$this->setStockOutDataForStockIn($value['id'],$value['quantity']);
		}
	}
	
	/**
	 * 修改入库导致指定出库数据发生变化时更新超出部分的出库信息
	 *
	 * @param int $stock_in_id  入库ID
	 * @param int $exceed_quantity	 入库数量
	 */
	private function setStockOutDataForStockIn($stock_in_id,$quantity){
		// 更新超出入库数量部分的出库记录
		$sql 			= 'select * from stock_out where stock_in_id='.$stock_in_id.' order by out_date asc,id asc';
		$detail 		= $this->db->query($sql);
		$out_quantity 	= 0;
		$flag			= false;
		foreach ((array)$detail as $value) {
			$out_quantity+=$value['quantity'];
			if ($out_quantity>=$quantity || $flag==true) {
				if ($flag==true) {
					$this->setStockOutDataForRelation($value);
				}else {
					$unfinish_quantity 	= $out_quantity-$quantity;
					$finish_quantity 	= $value['quantity']-$unfinish_quantity;
					$ary = array('id'=>$value['id'],'quantity'=>$finish_quantity);
					M('StockOut')->save($ary);
					$value['quantity']	= $unfinish_quantity;
					$this->setStockOutDataForRelation($value,false);
					$flag = true;
				}
			}
		}
	}
	
	
	/**
	 * 根据当前币种获取与本位币的汇率
	 *
	 * @param  $from_currency 币种ID
	 * @param   $date 转换日期
	 */
	private function getRate($from_currency,$rate_date){
		$rate_type 		= C('set_rate_type');
		$to_currency 	= C('currency');
		if($from_currency==$to_currency) return 1;
		import('ORG.Util.Date');
		$date = new Date($rate_date);
		switch ($rate_type) {
			case 1:
				$rate_info = M('FixedRate')->field('rate')->where('from_currency_id='.$from_currency.' and to_currency_id='.$to_currency)->find();
				break;
			case 2:
				$rate_info = M('RateInfo')->field('opened_y as rate')->where('from_currency_id='.$from_currency.' and to_currency_id='.$to_currency.' and rate_date=\''.$date->format('%Y-%m').'-01\'')->find();
				break;
			default:
				$rate_info = M('RateInfo')->field('opened_y as rate')->where('from_currency_id='.$from_currency.' and to_currency_id='.$to_currency.' and rate_date=\''.$date->format('%Y-%m-%d').'\'')->find();
				break;
		}
		// 找不到对应汇率时取固定汇率记录汇率错误日志，一天只记录一次
		if ($rate_info['rate']<=0) {
			$count = M('RateError')->where('error_date=\''.$date->format('%Y-%m-%d').'\' and from_currency_id='.$from_currency.' and to_currency_id='.$to_currency)->count();
			if ($count<=0) {
				M('RateError')->add(array('from_currency_id'=>$from_currency,'to_currency_id'=>$to_currency,'error_date'=>$rate_date));
			}
			$rate_info = M('FixedRate')->field('rate')->where('from_currency_id='.$from_currency.' and to_currency_id='.$to_currency)->find();
		}
		return $rate_info['rate'];
	}
	
	/**
	 * 还原出库记录
	 *
	 * @param int $out_id
	 * @param  string  $restore  是否还原对应入库记录
	 */
	private function restoreStockOut($out_id=null,$restore=true){
		if ($restore==false) {
			$del_data = M('StockOut')->find($out_id);
			return $this->execute('update stock_in set balance=0 where id='.$del_data['stock_in_id']); 
		}
		if ($out_id) {
			$del_data = M('StockOut')->where('id='.$out_id)->select();	
		}else {
			$del_data = M('StockOut')->where('main_id='.$this->params['id'].' and out_relation_type='.$this->relation_type)->select();	
		}
		foreach ((array)$del_data as $del_value) {
			$this->execute('update stock_in set balance=balance+'.$del_value['quantity'].' where id='.$del_value['stock_in_id']); 
		}
		if ($out_id) {
			M('StockOut')->where('id='.$out_id)->delete();
		}else {
			M('StockOut')->where('main_id='.$this->params['id'].' and out_relation_type='.$this->relation_type)->delete();
		}
		
	}
	
}